Inside Macintosh: Files

Previous | Chapter Top | Chapter Contents | Next

Closing a File

In most cases, your application closes a file after a user clicks in a window's close box or chooses the Close command in the File menu. The Close menu command should be active only when there is actually an active window on the desktop. If there is an active window, you need to determine whether it belongs to your application; if so, you need to handle dialog windows and document windows differently, as illustrated in Listing 1-15 .

Listing 15 Handling the Close menu command

FUNCTION DoCloseCmd: OSErr;
VAR
    myWindow:       WindowPtr;
    myData:         MyDocRecHnd;
    myErr:          OSErr;
BEGIN
    myErr := FALSE;
    myWindow := FrontWindow;                    {get window to be closed}
    CASE MyGetWindowType(myWindow) OF
        kDAWindow:
            CloseDeskAcc(WindowPeek(myWindow)^.windowKind);
        kMyModelessDialog:
            HideWindow(myWindow);               {for dialogs, hide the window}
        kMyDocWindow:
            BEGIN
                myData := MyDocRecHnd(GetWRefCon(myWindow));
                myErr := DoCloseFile(myData);
                IF myErr = noErr THEN
                    DisposeWindow(myWindow);
            END;
        OTHERWISE
            ;
    END;
    DoCloseCmd := myErr;
END;

The DoCloseCmd function determines the type of the frontmost window by calling the application-defined function MyGetWindowType . (See the chapter "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials for a definition of MyGetWindowType .) If the window to be closed is a window belonging to a desk accessory, DoCloseCmd closes the desk accessory. If the window to be closed is a dialog window, this procedure just hides the window. If the window to be closed is a document window, DoCloseCmd retrieves its document record handle and calls both DoCloseFile (defined in Listing 1-16 ) and DisposeWindow . Before you close the file associated with a window, you should check whether the contents of the window have changed since the last time the document was saved. If so, you should ask the user whether to save those changes. Listing 1-16 illustrates one way to do this.

Listing 16 Closing a file

FUNCTION DoCloseFile (myData: MyDocRecHnd): OSErr;
VAR
    myErr:          OSErr;
    myDialog:       DialogPtr;              {pointer to modal dialog box}
    myItem:         Integer;                {item selected in alert box}
    myPort:         GrafPtr;                {the original graphics port}
CONST
    kSaveChangesDialog = 129;               {resource of Save changes dialog}
BEGIN
    IF myData^^.windowDirty THEN            {see whether window is dirty}
        BEGIN
            myItem := CautionAlert(kSaveChangesDialog, NIL);
            IF myItem = iCancel THEN{user clicked Cancel}
                BEGIN
                    DoCloseFile := usrCanceledErr;
                    Exit(DoCloseFile);
                END;
            IF myItem = iSave THEN
                myErr := DoSaveCmd;
        END;
    IF myData^^.fileRefNum <> 0 THEN
        BEGIN
            myErr := FSClose(myData^^.fileRefNum);
            IF myErr = noErr THEN
                BEGIN
                    myErr := FlushVol(NIL, myData^^.fileFSSpec.vRefNum);
                    myData^^.fileRefNum := 0;           {clear the file reference number}
                END;
        END;
    {Dispose of TextEdit record and controls here (code omitted).}
    DisposeHandle(Handle(myData));                      {dispose of document record}
    DoCloseFile := myErr;
END;

If the document is an existing file that has not been changed since it was last saved, your application can simply call the FSClose function. This routine writes to disk any unwritten data remaining in the volume buffer. The FSClose function also updates the information maintained on the volume for that file and removes the access path. The information about the file is not actually written to the disk, however, until the volume is flushed, ejected, or unmounted. To keep the file information current, it's a good idea to follow each call to FSClose with a call to the FlushVol function.

If the contents of an existing file have been changed, or if a new file is being closed for the first time, your application can call the Dialog Manager routine CautionAlert (specifying a resource ID of an 'ALRT' template) to ask the user whether or not to save the changes. If the user decides not to save the file, you can just call FSClose and dispose of the window. Otherwise, DoCloseFile calls the DoSaveCmd function to save the file to disk.


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next